<template>
  <div class="a-grid" :class="gridClassList">
    <slot></slot>
  </div>
</template>

<script>
const BREAK_POINT_DEFAULT_PROPERTY = 'default';
const BREAK_POINT_PROPERTIES = [
  BREAK_POINT_DEFAULT_PROPERTY,
  'sm',
  'md',
  'lg',
  'xl',
  '2xl',
];

const GRID_COL = 'col';
const GRID_ROW = 'row';

export default {
  name: 'AGrid',
  props: {
    /**
     * 如果为Number类型，只支持 1 - 12
     *
     * 如果为Object类型
     *   属性名：只支持default、sm、md、lg、xl、2xl
     *   属性值：Number类型
     */
    col: {
      type: [Object, Number],
    },
    /**
     * 如果为 Number 类型，只支持 1 - 6
     *
     * 如果为 Object 类型
     *   属性名：只支持default、sm、md、lg、xl、2xl
     *   属性值：Number类型
     */
    row: {
      type: [Object, Number],
    },
    /**
     * 如果为 Number 类型，内部计算得到值
     *
     * 如果是 String 类型，可以使用CSS值，例如 12px、3%
     *
     * 如果为 Object 类型
     *   属性名：只支持 default、x、y
     *   属性值：可以是Object、String、Number
     *    - String、Number类型。如上所述
     *    - Object：
     *        属性名：只支持default、sm、md、lg、xl、2xl
     *        属性值：String、Number类型。如上所述
     */
    gap: {
      type: [Object, String, Number],
    },
  },
  computed: {
    gridClassList() {
      let result = ['grid'];

      let colClassList = this.calcGetGridClassList(this.col, GRID_COL);
      let rowClassList = this.calcGetGridClassList(this.row, GRID_ROW);

      let gapClassList = this.calcGetGapClassList(this.gap);

      return result.concat(colClassList, rowClassList, gapClassList);
    },
  },
  methods: {
    calcGetGridClassList(obj, type) {
      let result = [];

      let prefix = '';
      if (type === GRID_COL) {
        prefix = 'grid-cols';
      }
      if (type === GRID_ROW) {
        prefix = 'grid-rows';
      }

      if (typeof obj === 'number') {
        let val = obj;
        result.push(`${prefix}-${val}`);
        return result;
      }

      if (typeof obj === 'object') {
        let breakPointObjClassList = this.convertBreakPointObjToClassList(
          obj,
          prefix
        );

        return result.concat(breakPointObjClassList);
      }
    },
    calcGetGapClassList(gap) {
      let result = [];

      if (typeof gap === 'number' || typeof gap === 'string') {
        let handledVal = this.handleVal(gap);
        result.push(`gap-${handledVal}`);
        return result;
      }

      if (typeof gap === 'object') {
        if (gap.default) {
          let prefix = 'gap';

          if (
            typeof gap.default === 'number' ||
            typeof gap.default === 'string'
          ) {
            let handledVal = this.handleVal(gap.default);
            result.push(`${prefix}-${handledVal}`);
          }

          if (typeof gap.default === 'object') {
            result = result.concat(
              this.convertBreakPointObjToClassList(gap.default, prefix)
            );
          }
        }

        if (gap.x) {
          let prefix = 'gap-x';

          if (typeof gap.x === 'number' || typeof gap.x === 'string') {
            let handledVal = this.handleVal(gap.x);
            result.push(`${prefix}-${handledVal}`);
          }

          result = result.concat(
            this.convertBreakPointObjToClassList(gap.x, prefix)
          );
        }

        if (gap.y) {
          let prefix = 'gap-y';

          if (typeof gap.y === 'number' || typeof gap.y === 'string') {
            let handledVal = this.handleVal(gap.y);
            result.push(`${prefix}-${handledVal}`);
          }

          result = result.concat(
            this.convertBreakPointObjToClassList(gap.y, prefix)
          );
        }

        return result;
      }
    },
    /**
     * obj: {
     *   default,
     *   sm,
     *   md,
     *   lg,
     *   xl,
     *   2xl
     * }
     *
     * */
    convertBreakPointObjToClassList(obj, prefix) {
      let result = [];

      for (let breakPointProperty of BREAK_POINT_PROPERTIES) {
        let prefixResult = prefix;
        // 变体
        if (breakPointProperty !== BREAK_POINT_DEFAULT_PROPERTY) {
          prefixResult = `${breakPointProperty}:${prefixResult}`;
        }

        let val = obj[breakPointProperty];
        let handledVal = this.handleVal(val);

        result.push(`${prefixResult}-${handledVal}`);
      }

      return result;
    },
    handleVal(val) {
      if (typeof val === 'string') {
        return `[${val}]`;
      }
      return val;
    },
  },
};
</script>

<style scoped></style>
